﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Common;
using Ubatic.Common.Dto;
using Ubatic.Business.Helpers;
using System.Data;
using System.Transactions;
using Ubatic.EvaluacionProyectos.Data;

namespace Ubatic.Business.Managers
{
    public class UserManager
    {
        #region [Basic Operations]

        public int CreateIncompleteUser(Usuario userDto)
        {
            using (TransactionScope tScope = new TransactionScope())
            {
                using (CitepEvaluacionProyectosEntities ctx = new CitepEvaluacionProyectosEntities())
                {
                    DbUsuario dbUsuario = new DbUsuario();

                    dbUsuario.Email = userDto.Email;
                    dbUsuario.Password = userDto.Password;
                    dbUsuario.Nombre = userDto.Nombre;
                    dbUsuario.Apellido = userDto.Apellido;
                    dbUsuario.PreguntaSecreta = userDto.PreguntaSecreta;
                    dbUsuario.RespuestaSecreta = userDto.RespuestaSecreta;
                    if (!userDto.GuidMailConfirmacion.HasValue)
                    {
                        dbUsuario.GuidMailConfirmacion = Guid.NewGuid();
                    }
                    else
                    {
                        dbUsuario.GuidMailConfirmacion = userDto.GuidMailConfirmacion;
                    }

                    ctx.DbUsuario.AddObject(dbUsuario);

                    ctx.SaveChanges();

                    tScope.Complete();

                    userDto.Id = dbUsuario.Id;

                    return dbUsuario.Id;
                }
            }
        }

        public bool ActiveUser(Usuario userDto)
        {
            using (TransactionScope tScope = new TransactionScope())
            {
                using (CitepEvaluacionProyectosEntities ctx = new CitepEvaluacionProyectosEntities())
                {
                    DbUsuario dbUsuario = ctx.DbUsuario.Where(u => u.Id == userDto.Id).SingleOrDefault();

                    if (dbUsuario != null)
                    {
                        dbUsuario.Activo = true;
                        ctx.SaveChanges();

                        tScope.Complete();
                    }
                }
            }

            return true;
        }


        // #TODO: cambiar los datos del insert
        public int CreateUser(Usuario userDto)
        {
            using (TransactionScope tScope = new TransactionScope())
            {
                using (CitepEvaluacionProyectosEntities ctx = new CitepEvaluacionProyectosEntities())
                {
                    DbUsuario dbUsuario = new DbUsuario();

                    dbUsuario.Email = userDto.Email;
                    dbUsuario.Password = userDto.Password;
                    dbUsuario.Nombre = userDto.Nombre;
                    dbUsuario.Apellido = userDto.Apellido;
                    dbUsuario.CUIL = userDto.CUIL;
                    dbUsuario.TipoDocumentoId = userDto.TipoDocumentoId;
                    dbUsuario.NroDocumento = userDto.NroDocumento;
                    dbUsuario.Legajo = userDto.Legajo;
                    dbUsuario.Activo = userDto.Activo;
                    dbUsuario.PreguntaSecreta = userDto.PreguntaSecreta;
                    dbUsuario.RespuestaSecreta = userDto.RespuestaSecreta;
                    dbUsuario.PathCurriculumVitae = userDto.PathCurriculumVitae;
                    dbUsuario.UsuarioExperienciaDesc = userDto.UsuarioExperienciaDesc;

                    ctx.DbUsuario.AddObject(dbUsuario);

                    ctx.SaveChanges();

                    tScope.Complete();

                    return dbUsuario.Id;
                }
            }
        }

        public bool UpdateUser(Usuario userDto)
        {
            using (TransactionScope tScope = new TransactionScope())
            {
                using (CitepEvaluacionProyectosEntities ctx = new CitepEvaluacionProyectosEntities())
                {
                    DbUsuario dbUsuario = ctx.DbUsuario.Where(u => u.Id == userDto.Id).SingleOrDefault();

                    if (dbUsuario != null)
                    {
                        dbUsuario.Email = userDto.Email;
                        dbUsuario.Password = userDto.Password;
                        dbUsuario.Nombre = userDto.Nombre;
                        dbUsuario.Apellido = userDto.Apellido;
                        dbUsuario.CUIL = userDto.CUIL;
                        dbUsuario.TipoDocumentoId = userDto.TipoDocumentoId;
                        dbUsuario.NroDocumento = userDto.NroDocumento;
                        dbUsuario.Legajo = userDto.Legajo;
                        dbUsuario.Activo = userDto.Activo;
                        dbUsuario.PreguntaSecreta = userDto.PreguntaSecreta;
                        dbUsuario.RespuestaSecreta = userDto.RespuestaSecreta;
                        dbUsuario.PathCurriculumVitae = userDto.PathCurriculumVitae;
                        dbUsuario.UsuarioExperienciaDesc = userDto.UsuarioExperienciaDesc;

                        ctx.SaveChanges();

                        tScope.Complete();
                    }

                    return true;
                }
            }
        }

        public bool DeleteUser(long userId)
        {
            using (TransactionScope tScope = new TransactionScope())
            {
                using (CitepEvaluacionProyectosEntities ctx = new CitepEvaluacionProyectosEntities())
                {
                    DbUsuario dbUsuario = ctx.DbUsuario.Where(u => u.Id == userId).SingleOrDefault();

                    if (dbUsuario != null)
                    {
                        ctx.DbUsuario.DeleteObject(dbUsuario);
                        ctx.SaveChanges();
                        tScope.Complete();
                    }
                }
            }

            return true;
        }

        public Usuario GetUser(long userId)
        {
            Usuario usuario = null;
            using (CitepEvaluacionProyectosEntities ctx = new CitepEvaluacionProyectosEntities())
            {
                DbUsuario dbUsuario = ctx.DbUsuario.Where(u => u.Id == userId).SingleOrDefault();

                if (dbUsuario != null)
                {
                    usuario = new Usuario();
                    FillUserFromDbUser(usuario, dbUsuario);                    
                }
            }

            return usuario;
        }

        public Usuario GetUserByEmail(string email)
        {
            Usuario usuario = null;
            using (CitepEvaluacionProyectosEntities ctx = new CitepEvaluacionProyectosEntities())
            {
                DbUsuario dbUsuario = ctx.DbUsuario.Where(u => u.Email == email).SingleOrDefault();

                if (dbUsuario != null)
                {
                    usuario = new Usuario();
                    FillUserFromDbUser(usuario, dbUsuario);
                }
            }

            return usuario;
        }

        private void FillUserFromDbUser(Usuario usuario, DbUsuario dbUsuario)
        {
            usuario.Id = dbUsuario.Id;
            usuario.Email = dbUsuario.Email;
            usuario.Password = dbUsuario.Password;
            usuario.Nombre = dbUsuario.Nombre;
            usuario.Apellido = dbUsuario.Apellido;
            usuario.CUIL = dbUsuario.CUIL;
            usuario.TipoDocumentoId = dbUsuario.TipoDocumentoId;
            usuario.NroDocumento = dbUsuario.NroDocumento;
            usuario.Legajo = dbUsuario.Legajo;
            usuario.Activo = dbUsuario.Activo;
            usuario.PreguntaSecreta = dbUsuario.PreguntaSecreta;
            usuario.RespuestaSecreta = dbUsuario.RespuestaSecreta;
            usuario.PathCurriculumVitae = dbUsuario.PathCurriculumVitae;
            usuario.UsuarioExperienciaDesc = dbUsuario.UsuarioExperienciaDesc;
            usuario.GuidMailConfirmacion = dbUsuario.GuidMailConfirmacion;
        }

        private Usuario GetUserFromDbUser(DbUsuario dbUsuario)
        {
            Usuario usuario = new Usuario();
            FillUserFromDbUser(usuario, dbUsuario);
            return usuario;
        }

        public Usuario GetUser(string email)
        {
            Usuario usuario = null;
            using (CitepEvaluacionProyectosEntities ctx = new CitepEvaluacionProyectosEntities())
            {
                DbUsuario dbUsuario = ctx.DbUsuario.Where(u => u.Email == email).SingleOrDefault();

                if (dbUsuario != null)
                {
                    usuario = new Usuario();
                    FillUserFromDbUser(usuario, dbUsuario);
                }
            }

            return usuario;
        }

        public List<Usuario> GetUsers()
        {            
            using (CitepEvaluacionProyectosEntities ctx = new CitepEvaluacionProyectosEntities())
            {
                List<Usuario> usuarioList = new List<Usuario>();
                foreach(var dbUsuario in ctx.DbUsuario)
                {
                    usuarioList.Add(GetUserFromDbUser(dbUsuario));
                }

                return usuarioList;
                
            }            
        }

        #endregion [Basic Operations]

        public void AddUserToRoles(Usuario userDto, List<long> roles)
        {
            string commandText = @"INSERT INTO [UsuarioRol]
                                               (UsuarioId,RolId)
                                         VALUES
                                               (@UserId,@RoleId)";

            using (DbConnection connection = DbHelper.CreateDbConnection())
            {
                connection.Open();

                DbCommand command = connection.CreateCommand();
                DbTransaction transaction;

                transaction = connection.BeginTransaction();

                command.Connection = connection;
                command.Transaction = transaction;

                command.CommandText = commandText;
                command.Prepare();
                /// Parametro IdUsuario
                DbParameter parameter = command.CreateParameter();
                parameter.ParameterName = "UserId";
                command.Parameters.Add(parameter);
                /// Parametro IdRol
                parameter = command.CreateParameter();
                parameter.ParameterName = "RoleId";
                command.Parameters.Add(parameter);

                try
                {
                    for (int i = 0; i < roles.Count(); i++)
                    {
                        command.Parameters["UserId"].Value = userDto.Id;
                        command.Parameters["RoleId"].Value = roles[i];
                        command.ExecuteNonQuery();
                    }

                    transaction.Commit();
                }
                catch
                {
                    transaction.Rollback();
                    throw;
                }
            }
        }

        public void RemoveUserFromRoles(Usuario userDto, List<long> roles)
        {
            string commandText = @"DELETE FROM [UsuarioRol]
                                    WHERE UsuarioId= @UserId
                                      AND RolId=@RoleId";

            using (DbConnection connection = DbHelper.CreateDbConnection())
            {
                connection.Open();

                DbCommand command = connection.CreateCommand();

                command.Connection = connection;

                command.CommandText = commandText;
                command.Prepare();
                /// Parametro IdUsuario
                DbParameter parameter = command.CreateParameter();
                parameter.ParameterName = "UserId";
                command.Parameters.Add(parameter);
                /// Parametro IdRol
                parameter = command.CreateParameter();
                parameter.ParameterName = "RoleId";
                command.Parameters.Add(parameter);

                try
                {
                    for (int i = 0; i < roles.Count(); i++)
                    {
                        command.Parameters["UserId"].Value = userDto.Id;
                        command.Parameters["RoleId"].Value = roles[i];
                        command.ExecuteNonQuery();
                    }
                }
                catch
                {
                    throw;
                }
            }
        }

        public bool ChangePassword(long userId, string newPassword)
        {
            int result = 0;
            string queryString = @"UPDATE [Usuario]
                                       SET [Password] = @newPassword
                                     WHERE Id=@Id";

            using (DbConnection connection = DbHelper.CreateDbConnection())
            {
                connection.Open();

                DbCommand command = connection.CreateCommand();
                DbTransaction transaction;

                // Start a local transaction.
                transaction = connection.BeginTransaction();

                // Must assign both transaction object and connection
                // to Command object for a pending local transaction
                command.Connection = connection;
                command.Transaction = transaction;
                command.CommandText = queryString;

                DbHelper.AddCommandParameter(command, "newPassword", newPassword);
                DbHelper.AddCommandParameter(command, "Id", userId);

                try
                {
                    result = command.ExecuteNonQuery();
                    transaction.Commit();
                }
                catch
                {
                    transaction.Rollback();
                    throw;
                }
                finally
                {
                    if (connection != null)
                        connection.Close();
                }

                return (result > 0);
            }
        }

        //        public List<UsuarioDto> GetUsers(UserSearchDto search)
        //        {
        //            List<UsuarioDto> users = new List<UsuarioDto>();
        //            string queryString = @"SELECT * 
        //                                     FROM Usuario
        //                                    WHERE (@firstName = '' OR Nombre LIKE '%' + @firstName + '%')
        //                                      AND (@lastName = '' OR Apellido LIKE '%' + @lastName + '%')
        //                                      AND (@email = '' OR Email LIKE '%' + @email + '%')";
        //            using (DbConnection connection = DbHelper.CreateDbConnection())
        //            {
        //                DbCommand command = connection.CreateCommand();
        //                command.CommandText = queryString;

        //                // Search Parameters
        //                DbHelper.AddCommandParameter(command, "firstName", search.FirstName);
        //                DbHelper.AddCommandParameter(command, "lastName", search.LastName);
        //                DbHelper.AddCommandParameter(command, "userName", search.UserName);
        //                DbHelper.AddCommandParameter(command, "email", search.Email);

        //                connection.Open();
        //                DbDataReader reader = command.ExecuteReader();
        //                try
        //                {
        //                    if (reader.HasRows)
        //                    {
        //                        while (reader.Read())
        //                        {
        //                            users.Add(UserManager.ToUsuarioDto(reader));

        //                        }
        //                    }
        //                }
        //                finally
        //                {
        //                    // Always call Close when done reading.
        //                    reader.Close();
        //                }
        //            }
        //            return users;
        //        }

        public static Usuario ToUsuarioDto(DbDataReader reader)
        {
            Usuario dto = new Usuario();

            dto.Id = Int32.Parse(reader["Id"].ToString());
            dto.Email = reader["Email"].ToString();
            dto.Password = reader["Password"].ToString();
            dto.Nombre = reader["Nombre"].ToString();
            dto.Apellido = reader["Apellido"].ToString();
            dto.CUIL =reader["CUIL"].ToString();
            dto.TipoDocumentoId = BuilderHelper.GetNullableInt(reader["TipoDocumentoId"].ToString());
            dto.NroDocumento = BuilderHelper.GetNullableLong(reader["NroDocumento"].ToString());
            dto.Legajo = BuilderHelper.GetNullableInt(reader["Legajo"].ToString());
            dto.Activo = bool.Parse(reader["Activo"].ToString());
            dto.PreguntaSecreta = reader["PreguntaSecreta"].ToString();
            dto.RespuestaSecreta = reader["RespuestaSecreta"].ToString();
            dto.PathCurriculumVitae = reader["PathCurriculumVitae"].ToString();
            dto.UsuarioExperienciaDesc = reader["UsuarioExperienciaDesc"].ToString();
            dto.GuidMailConfirmacion = Guid.Parse(reader["GuidMailConfirmacion"].ToString());

            return dto;
        }

        internal bool RemoveUserFromAllRoles(long userId)
        {
            int result = 0;
            string queryString = "DELETE FROM UsuarioRol WHERE UsuarioId=@userId;";
            using (DbConnection connection = DbHelper.CreateDbConnection())
            {
                connection.Open();
                DbCommand command = connection.CreateCommand();

                command.CommandText = queryString;
                DbHelper.AddCommandParameter(command, "userId", userId);

                try
                {
                    result = command.ExecuteNonQuery();
                }
                catch
                {
                    throw;
                }
                finally
                {
                    if (connection.State == ConnectionState.Open)
                        connection.Close();
                }
            }
            return (result > 0);
        }
    }
}
